package com.example.testimagematrix

import android.graphics.Matrix
import android.graphics.Point
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.example.testimagematrix.databinding.FragmentFirstBinding
import kotlin.math.atan
import kotlin.math.atan2
import kotlin.math.sqrt

/**
 * A simple [Fragment] subclass as the default destination in the navigation.
 */
class FirstFragment : Fragment() {

    private val TAG = "TestImageMatrix"
    private var _binding: FragmentFirstBinding? = null

    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {

        _binding = FragmentFirstBinding.inflate(inflater, container, false)
        return binding.root

    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.image640.setImageResource(R.mipmap.fpt_thumb)
        binding.image1080.setImageResource(R.mipmap.fpt_thumb)

        var firstClick = true

        binding.image1080.setOnTouchListener(object : View.OnTouchListener {
            override fun onTouch(v: View?, event: MotionEvent?): Boolean {
                // 获取点坐标
                val x = event!!.x
                val y = event.y
                Log.d(TAG, "点按坐标: ($x, $y)")
                // 获取矩阵信息
                val matrix = Matrix()
                binding.image1080.getSuppMatrix(matrix)
                val data = FloatArray(9)
                matrix.getValues(data)

                // 转换点坐标
                val point = floatArrayOf(x, y)
                matrix.mapPoints(point)
                Log.d(TAG, "矩阵对点转换结果: (${point[0]}, ${point[1]})")
                // 计算偏移量
                val scale: Float = binding.image1080.scale
                val offsetX: Float = data[2]
                val offsetY: Float = data[5]
                Log.d(TAG, "矩阵偏移量: ($offsetX, $offsetY)")
                // 计算最终坐标
                val finalX: Float = point[0] * scale - offsetX
                val finalY: Float = point[1] * scale - offsetY
                // 输出最终坐标
                Log.d(TAG, "最终坐标: ($finalX, $finalY)")

                return true
            }
        })

        binding.buttonFirst.setOnClickListener {
//            findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment)

            val bmpWidth = binding.image640.width.toFloat()
            val bmpHeight = binding.image640.height.toFloat()
            val showWidth = binding.image1080.width.toFloat()
            val showHeight = binding.image1080.height.toFloat()

            val matrix = Matrix()
            binding.image1080.getSuppMatrix(matrix)
            Log.d(TAG, "supp matrix = $matrix")

            // scale 放大的点是按view的宽高在缩放
            if (firstClick) {
                matrix.setScale(3f, 3f, showWidth / 2f, showHeight / 2f)
                Log.d(TAG, "supp scale after matrix = $matrix")
                firstClick = false
            }

            // 还是得研究下偏移量，就是偏移屏幕像素量
            matrix.postTranslate(360f, 0f)
            Log.d(TAG, "supp translate after matrix = $matrix")

            // 旋转本身受view边界的限制，旋转时超出边界会被强制拉回。
            // 旋转本身会增加整张图片的宽高，0|90|180|270宽高都是不变的，其它角度都会增加，45度是增加最大。
            // 在没超过图像边界的情况下，也是按view的宽高对应的图像位置旋转。preRotate不好把控。
            // 后面不传中心点默认是以(0, 0)点旋转
            matrix.postRotate(90f, showWidth / 2f, showWidth / 2f)
            Log.d(TAG, "supp rotate after matrix = $matrix")

            // 对于一个相对于视图的坐标点，在经过矩阵变换后的结果
            val matrixData = FloatArray(9)
            matrix.getValues(matrixData)

            // 计算将view(0, 0)点矩阵变换后点view点位
            val testX = 1080f
            val testY = 1080f
            val testZ = 1f
            val resultX = matrixData[0] * testX + matrixData[1] * testY + matrixData[2] * testZ
            val resultY = matrixData[3] * testX + matrixData[4] * testY + matrixData[5] * testZ
            val resultZ = matrixData[6] * testX + matrixData[7] * testY + matrixData[8] * testZ
            Log.d(TAG, "matrix trans point before = $testX, $testY, $testZ")
            Log.d(TAG, "matrix trans point after = $resultX, $resultY, $resultZ")

            val result = FloatArray(2)
            matrix.mapPoints(result, floatArrayOf(testX, testY))
            Log.d(TAG, "matrix trans point before = $testX, $testY, $testZ")
            Log.d(TAG, "matrix trans point other method after = ${result[0]}, ${result[1]}")

            // 对于变换后的点，通过逆矩阵重新计算为之前的视图坐标点
            val inverseMatrix = Matrix()
            matrix.invert(inverseMatrix)
            Log.d(TAG, "photo view matrix 逆矩阵 = $inverseMatrix")
            val inverseMatrixData = FloatArray(9)
            inverseMatrix.getValues(inverseMatrixData)
            val originX = inverseMatrixData[0] * resultX + inverseMatrixData[1] * resultY + inverseMatrixData[2] * resultZ
            val originY = inverseMatrixData[3] * resultX + inverseMatrixData[4] * resultY + inverseMatrixData[5] * resultZ
            val originZ = inverseMatrixData[6] * resultX + inverseMatrixData[7] * resultY + inverseMatrixData[8] * resultZ
            Log.d(TAG, "matrix inverse point after = $originX, $originY, $originZ")

            binding.image1080.setSuppMatrix(matrix)
            Log.d(TAG, "image 1080 image matrix = ${binding.image1080.imageMatrix}")


            // 重中之重：对于旋转过的图片，将屏幕的点按位置转到图片上的实际位置
            // 错误尝试1：得到的坐标和屏幕坐标是一一对应的固定关系，屏幕坐标相对于屏幕的位置 映射到 像素坐标相对图片的位置。
            val imageData = FloatArray(9)
            binding.image1080.imageMatrix.getValues(imageData)
            Log.d(TAG, "image matrix = ${imageData.contentToString()}")
            val imageX = (resultX - imageData[2])
            val imageY = (resultY - imageData[5])
            Log.d(TAG, "view ($testX, $testY) is image point = $imageX, $imageY")

            // 错误尝试2：屏幕坐标加减了矩阵偏移量，再做逆矩阵计算本身思路就错误了，应该直接对屏幕坐标做逆矩阵计算。
            // 并且用屏幕坐标做图像矩阵的逆矩阵计算可能也是个错误思路。
            val inverseImageMatrix = Matrix()
            binding.image1080.imageMatrix.invert(inverseImageMatrix)
            val finalResult = FloatArray(2)
            Log.d(TAG, "matrix trans point before = $testX, $testY, $testZ")
            val cnmX = testX - imageData[2]
            val cnmY = testY - imageData[5]
            Log.d(TAG, "cnmX = $cnmX, cnmY = $cnmY")
            inverseImageMatrix.mapPoints(finalResult, floatArrayOf(cnmX, cnmY))
            Log.d(TAG, "view ($testX, $testY) is origin image point = ${finalResult[0]}, ${finalResult[1]}")

            // 正确计算：屏幕坐标直接做SuppMatrix的逆矩阵运算，再乘以图像scale除以View scale
            val testMatrix = Matrix()
            binding.image1080.getSuppMatrix(testMatrix)
            val inverseSuppMatrix = Matrix()
            testMatrix.invert(inverseSuppMatrix)
            inverseSuppMatrix.mapPoints(finalResult, floatArrayOf(testX, testY))
            Log.d(TAG, "view ($testX, $testY) suppMatrix invert = ${finalResult[0]}, ${finalResult[1]}")
            val originImgX = finalResult[0] * bmpWidth / showWidth
            val originImgY = finalResult[1] * bmpHeight / showHeight
            Log.d(TAG, "view ($testX, $testY) is origin image point = $originImgX, $originImgY")


            // 正确计算优化：直接用屏幕坐标做ImageMatrix的逆矩阵运算
            inverseImageMatrix.mapPoints(finalResult, floatArrayOf(testX, testY))
            Log.d(TAG, "view ($testX, $testY) is origin image point = ${finalResult[0]}, ${finalResult[1]}")
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        _binding = null
    }
}